/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
//
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation;
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Author: George F. Riley<riley@ece.gatech.edu>
//

// ns3 - On/Off Data Source Application class
// George F. Riley, Georgia Tech, Spring 2007
// Adapted from ApplicationFlow in GTNetS.

#ifndef __flow_application_h__
#define __flow_application_h__

#include "ns3/address.h"
#include "ns3/application.h"
#include "ns3/event-id.h"
#include "ns3/ptr.h"
#include "ns3/data-rate.h"
#include "ns3/random-variable.h"
#include "ns3/traced-callback.h"

#include "ns3/tcp-socket-factory.h"


namespace ns3 {

class Address;
class RandomVariable;
class Socket;

/**
 * \ingroup applications 
 * \defgroup Flow FlowApplication
 *
 * This traffic generator follows an On/Off pattern: after 
 * Application::StartApplication
 * is called, "On" and "Off" states alternate. The duration of each of
 * these states is determined with the onTime and the offTime random
 * variables. During the "Off" state, no traffic is generated.
 * During the "On" state, cbr traffic is generated. This cbr traffic is
 * characterized by the specified "data rate" and "packet size".
 */
 /**
 * \ingroup Flow
 *
 * \brief Generate traffic to a single destination according to an
 *        Flow pattern.
 *
 * This traffic generator follows an On/Off pattern: after 
 * Application::StartApplication
 * is called, "On" and "Off" states alternate. The duration of each of
 * these states is determined with the onTime and the offTime random
 * variables. During the "Off" state, no traffic is generated.
 * During the "On" state, cbr traffic is generated. This cbr traffic is
 * characterized by the specified "data rate" and "packet size".
 *
 * Note:  When an application is started, the first packet transmission
 * occurs _after_ a delay equal to (packet size/bit rate).  Note also,
 * when an application transitions into an off state in between packet
 * transmissions, the remaining time until when the next transmission
 * would have occurred is cached and is used when the application starts
 * up again.  Example:  packet size = 1000 bits, bit rate = 500 bits/sec.
 * If the application is started at time 3 seconds, the first packet
 * transmission will be scheduled for time 5 seconds (3 + 1000/500)
 * and subsequent transmissions at 2 second intervals.  If the above
 * application were instead stopped at time 4 seconds, and restarted at
 * time 5.5 seconds, then the first packet would be sent at time 6.5 seconds,
 * because when it was stopped at 4 seconds, there was only 1 second remaining
 * until the originally scheduled transmission, and this time remaining
 * information is cached and used to schedule the next transmission
 * upon restarting.
 */

class Flow : public Object
{
public: 
  static TypeId GetTypeId (void);  

  Flow ();
  ~Flow ();

  void SetNode(Ptr<Node> node);
  void SetRemote(const Address &peer);
  void SetFinishCallback( Callback<void, Ptr<Flow> > flowFinished );

  void Start(uint32_t size);
  void Restart(uint32_t size = 0);
  void End();

  uint32_t GetSize();
  Time GetDuration();

private:
  void HandleSend(Ptr<Socket> socket, uint32_t dataSent);
  void HandleClose(Ptr<Socket> socket);

  uint32_t m_flowSize;
  uint32_t m_dataToSend;
  uint32_t m_txMax;
  Ptr<Socket> m_socket;
  Ptr<Node> m_node;
  Address  m_remote;

  Time m_startTime;
  Time m_endTime;
  Callback<void, Ptr<Flow> > m_flowFinished;
};
         
class FlowSink : public Object
{
public: 
  static TypeId GetTypeId (void);  

  FlowSink ();
  ~FlowSink () {}
  void SetSocket(Ptr<Socket> socket);
  void End();

private:
  void HandleRead(Ptr<Socket> socket);
  void Closed(Ptr<Socket> socket) {}
  
  Ptr<Socket> m_socket;
  uint32_t m_dataToRecv;
};
         
class FlowApplication : public Application 
{
public:
  static TypeId GetTypeId (void);

  FlowApplication ();
  virtual ~FlowApplication();

protected:
  virtual void DoDispose (void);
private:
  // inherited from Application base class.
  virtual void StartApplication (void);    // Called at time specified by Start
  virtual void StopApplication (void);     // Called at time specified by Stop

  void HandleAccept (Ptr<Socket>, const Address& from);
  void FlowFinishedCallback(Ptr<Flow> flow);

  Address         m_remote;       // Remote address
  Address         m_local;        // Local address
  RandomVariable  m_flowSize;     // Flow size
  uint32_t        m_flowNum;      // number of concurrent flows

  Ptr<Socket>               m_socket;       // Listening socket
  std::list<Ptr<FlowSink> > m_sinkList;   //the accepted sockets
  std::list<Ptr<Flow> >     m_flowList;   //the accepted sockets
  
  //returns to caller for logging
  Callback<void, uint32_t, Time > m_statCallback;

};

} // namespace ns3

#endif

